package com.yanqu.road.server.manager.union.activitygroup;

import com.yanqu.road.dao.impl.servercenter.CrossServerInfoDaoImpl;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eUnionActivityGroupType;
import com.yanqu.road.entity.enums.eUnionPosition;
import com.yanqu.road.entity.player.CrossUserBaseInfo;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.servercenter.CrossServerInfo;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.entity.union.UnionMember;
import com.yanqu.road.entity.union.activitygroup.*;
import com.yanqu.road.entity.union.cross.CrossUnionInfo;
import com.yanqu.road.entity.union.cross.CrossUnionMember;
import com.yanqu.road.logic.bussiness.servercenter.ActivityBussiness;
import com.yanqu.road.logic.bussiness.union.activitygroup.UnionActivityGroupBusiness;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.helper.MathHelper;
import com.yanqu.road.logic.helper.UnionActivityGroupHelper;
import com.yanqu.road.logic.pb.UnionActivityGroupPb;
import com.yanqu.road.logic.thread.ThreadTaskManger;
import com.yanqu.road.pb.union.UnionActivityGroupProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.union.CrossUnionConfigMgr;
import com.yanqu.road.server.manager.union.CrossUnionMgr;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.manger.CrossUnionServerGroupMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.protocol.AgentProtocol;
import com.yanqu.road.server.protocol.CrossProtocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.CrossServerType;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class UnionActivityGroupLockMgr extends TempMgr {

    private static AtomicInteger crossIndex = new AtomicInteger(new Random().nextInt(100));
    private static List<CrossServerInfo> activityCrossList = new ArrayList<>();
    private static final Object lock = new Object();

    /**
     * 商会活动信息    key：活动ID
     */
    private static Map<Integer, ActivityInfo> activityInfoMap = new ConcurrentHashMap<>();

    /**
     * 活动配置    key：活动ID，param
     */
    private static Map<Integer, Map<String, ActivityConfig>> activityConfigMap = new ConcurrentHashMap<>();

    /**
     * 分组规则    谁跟谁不分在一个组
     */
    private static List<UnionActivityGroupRule> groupRuleList = new ArrayList<>();

    private static ThreadTaskManger threadTaskManger;

    /**
     * 重新加载活动信息
     */
    public static void reloadUnionActivityConfig() {
        String nowTimeStr = DateHelper.getCurrentDateTimeString();
        Map<Integer, ActivityInfo> tempInfoMap = ActivityBussiness.getNoEndActivityInfoMap(UnionActivityGroupHelper.getActivityTypeList(), nowTimeStr);

        // zkt todo 热更代码记得优化 2023年3月28日16:05:55
        // 过滤非本渠道活动
        int channelId = ConfigHelper.getInt("channelId");
        for (Map.Entry<Integer, ActivityInfo> entry : tempInfoMap.entrySet()) {
            int activityId = entry.getKey();
            ActivityInfo info = entry.getValue();
            boolean channelCorrect = false;
            for (long serverId : info.getServerIdList()) {
                ServerInfo serverInfo = ServerListMgr.getServerInfo(serverId);
                if (serverInfo == null) {
                    continue;
                }
                channelCorrect = serverInfo.getChannelId() == channelId;
                break;
            }
            if (!channelCorrect) {
                tempInfoMap.remove(activityId);
            }
        }

        // 内网测试处理
        UnionActivityGroupLockTest.handleTestServerList(tempInfoMap);

        Map<Integer, Map<String, ActivityConfig>> tempConfigMap = ActivityBussiness.getActivityConfigMap(new ArrayList<>(tempInfoMap.keySet()));

        activityInfoMap = tempInfoMap;
        activityConfigMap = tempConfigMap;
        getLogger().debug("reload success.");

        // 刷新活动，或者0点重新加载后，马上检查分组和同步分组
        checkGrouping();
        checkSyncGroupInfo();
    }

    /**
     * 检查分组
     */
    public static void checkGrouping() {
        long now = System.currentTimeMillis();
        for (ActivityInfo activityInfo : activityInfoMap.values()) {
            if (!Cross3UnionActivityGroupMgr.haveGroup(activityInfo.getActivityId()) && now > UnionActivityGroupHelper.getGroupTime(activityInfo)) {
                grouping(activityInfo);
            }
        }
    }

    /**
     * 按商会分组 每组top  进行筛选资格
     */
    private static void unionPhaseWarGrouping(ActivityInfo activityInfo){
        Map<Integer, List<Long>> unionGroupMap = new HashMap<>();
        for (long serverId : activityInfo.getServerIdList()) {
            int groupId = CrossUnionServerGroupMgr.getGroupIdByServerId(serverId);
            if(!unionGroupMap.containsKey(groupId)){
                unionGroupMap.put(groupId, new ArrayList<>());
            }
            unionGroupMap.get(groupId).add(serverId);
        }

        List<Integer> paramList = StringUtils.stringToIntegerList(activityInfo.getUnionGroup(), "\\|");
        if(paramList.size() < 2){
            getLogger().info("activity {} grouping error {}", activityInfo.getActivityId(), activityInfo.getUnionGroup());
            return;
        }
        //第二个参数，总商会数
        int totalNum = paramList.get(1);
        if(totalNum % 4 != 0){
            //总商会数量不是4的倍数
            getLogger().info("activity {} grouping error {}", activityInfo.getActivityId(), activityInfo.getUnionGroup());
            return;
        }
        if(totalNum % activityInfo.getServerIdList().size() != 0){
            getLogger().info("activity {} grouping error {}", activityInfo.getActivityId(), activityInfo.getUnionGroup());
            return;
        }
        //每个区服个数
        int num = totalNum / activityInfo.getServerIdList().size();
        List<CrossUnionInfo> resultList = new ArrayList<>();
        //商会赚速排名
        Map<String, Integer> unionRankMap = new HashMap<>();
        int toAdd = 0;   //待补充人数
        for (Map.Entry<Integer, List<Long>> listEntry : unionGroupMap.entrySet()) {
            if(listEntry.getValue().size() == 1){
                //未启用商会分组的
                long serverId = listEntry.getValue().get(0);
                List<CrossUnionInfo> unionList = CrossUnionMgr.getUnionListInSameGroup(serverId);
                unionList.sort((o1, o2) -> o2.getTotalEarnSpeed().compareTo(o1.getTotalEarnSpeed()));
                if(unionList.size() < num){
                    getLogger().info("activity {} grouping error {}, server {} union size {}", activityInfo.getActivityId(), serverId, serverId, unionList.size());
                    //return;
                    toAdd += num - unionList.size();
                }
                for (int i = 0; i < num && i < unionList.size(); i++) {
                    resultList.add(unionList.get(i));
                    unionRankMap.put(unionList.get(i).getUnionUid(), i + 1);
                }

            } else if(listEntry.getValue().size() > 0){

                int numInGroup = num * listEntry.getValue().size();
                //分组各取前 num * 区服个数
                List<CrossUnionInfo> unionList = CrossUnionMgr.getUnionListByServerList(new HashSet<>(listEntry.getValue()));

                unionList.sort((o1, o2) -> o2.getTotalEarnSpeed().compareTo(o1.getTotalEarnSpeed()));

                if(unionList.size() < numInGroup){
                    getLogger().info("activity {} grouping error {}, union group {} union size {}", activityInfo.getActivityId(), listEntry.getKey(), listEntry.getKey(), unionList.size());
                    return;
                }
                for (int i = 0; i < unionList.size() && i < numInGroup; i++) {
                    resultList.add(unionList.get(i));
                    unionRankMap.put(unionList.get(i).getUnionUid(), i + 1);
                }
                for (int i = numInGroup; i < unionList.size() && toAdd > 0; i++) {
                    resultList.add(unionList.get(i));
                    unionRankMap.put(unionList.get(i).getUnionUid(), i + 1);
                    toAdd--;
                }
            }
        }

        if(resultList.size() != totalNum){
            getLogger().info("activity {} grouping error {}, union size {}", activityInfo.getActivityId(), activityInfo.getUnionGroup(), resultList.size());
            return;
        }

        // 生成数据
        Map<Integer, UnionActivityGroup> groupMap = new ConcurrentHashMap<>();

        ConcurrentHashMap<String, UnionActivityGroupUnion> map = new ConcurrentHashMap<>();
        for (CrossUnionInfo crossUnionInfo : resultList) {
            UnionActivityGroupUnion activityGroupUnion = createUnionActivityGroupUnion(activityInfo, 0, crossUnionInfo);
            int rank = unionRankMap.getOrDefault(crossUnionInfo.getUnionUid(), 0);
            if(rank > 0){
                activityGroupUnion.setRank(rank);
                activityGroupUnion.setLocked(1);
            }
            activityGroupUnion.setAbility(crossUnionInfo.getTotalEarnSpeed().toString());
            map.put(crossUnionInfo.getUnionUid(), activityGroupUnion);
        }

        //补竞猜资格名单
        // 获取可选商会
        List<CrossUnionInfo> unionList = getActivityUnionList(activityInfo);
        int groupNum = 1; // 分几组
        int unionNum = 1600; // 每组多少个商会 zkt todo 后续改小一点
        // 取前N名参与
        unionList = unionList.stream().sorted(Comparator.comparing(CrossUnionInfo::getTotalEarnSpeed).reversed()).limit(groupNum * unionNum).collect(Collectors.toList());
        for (CrossUnionInfo unionInfo : unionList) {
            if(map.containsKey(unionInfo.getUnionUid())){
                continue;
            }
            map.put(unionInfo.getUnionUid(), createUnionActivityGroupUnion(activityInfo, 0, unionInfo));
        }

        UnionActivityGroup group = new UnionActivityGroup();
        group.setActivityId(activityInfo.getActivityId());
        group.setGroupId(0);
        group.setCrossServerIdNeedSync(activityInfo.getCrossId().intValue());
        group.setServerSetNeedSync(calcServerIdSet(activityInfo, map));
        group.setUnionDataMap(map);
        group.setInsertOption();

        groupMap.put(group.getGroupId(), group);

        // 添加数据
        Cross3UnionActivityGroupMgr.putGroupMap(activityInfo.getActivityId(), groupMap);
        // 马上保存一下，没成功的话就交给定时器重试了
        Cross3UnionActivityGroupMgr.saveDbData();
        // 日志
        getLogger().debug("activity {} group success.", activityInfo.getActivityId());

        for (UnionActivityGroup activityGroup : groupMap.values()) {
            getLogger().debug("activity {} group {} size {}.", activityInfo.getActivityId(), activityGroup.getGroupId(), activityGroup.getUnionDataMap().size());
        }
    }

    /**
     * 分组
     */
    private static void grouping(ActivityInfo info) {
        eUnionActivityGroupType groupType = eUnionActivityGroupType.getType(info.getType());
        if (groupType == null) {
            return;
        }
        // 生成数据
        Map<Integer, UnionActivityGroup> groupMap = new ConcurrentHashMap<>();
        // 获取可选商会
        List<CrossUnionInfo> unionList = getActivityUnionList(info);
        // 分组参数
        int groupNum = 1; // 分几组
        int unionNum = 1600; // 每组多少个商会 zkt todo 后续改小一点
        boolean needGroup = UnionActivityGroupHelper.needGroup(info);
        if (needGroup) {
            groupNum = UnionActivityGroupHelper.getGroupNum(info);
            unionNum = UnionActivityGroupHelper.getRealGroupUnionNum(info, unionList.size());
        } else if (groupType.isLockMember()) {
            if (!info.getUnionGroup().equals("0")) {
                unionNum = UnionActivityGroupHelper.getRealGroupUnionNum(info, unionList.size());
            }
        }

        // 取前N名参与
        if (info.getType() == eActivityType.SuiTang.getValue()
                || info.getType() == eActivityType.ChuHanZB.getValue()) {
            // v6.9 改为赚钱
            unionList = unionList.stream().sorted(Comparator.comparing(CrossUnionInfo::getTotalMaxAbility).reversed()).limit(groupNum * unionNum).collect(Collectors.toList());
        } else {
            unionList = unionList.stream().sorted(Comparator.comparing(CrossUnionInfo::getTotalEarnSpeed).reversed()).limit(groupNum * unionNum).collect(Collectors.toList());
        }

        // 多次分组取最佳结果
        List<List<CrossUnionInfo>> bestRandomGroupResult = getBestRandomGroupResult(info, unionList, groupNum, 10, unionNum);

        // 分组
        Map<Integer, List<CrossUnionInfo>> listMap = new HashMap<>();
        int tempGroupId = needGroup ? UnionActivityGroupHelper.NEED_GROUP_FIRST_ID : UnionActivityGroupHelper.NO_NEED_GROUP_ID;
        if (info.getType() == eActivityType.SuiTang.getValue()
                || info.getType() == eActivityType.ChuHanZB.getValue()) {
            for (List<CrossUnionInfo> list : bestRandomGroupResult) {
                list.sort((o1, o2) -> o2.getTotalMaxAbility().compareTo(o1.getTotalMaxAbility()));
                listMap.put(tempGroupId++, new ArrayList<>(list));
            }
        } else {
            for (List<CrossUnionInfo> list : bestRandomGroupResult) {
                list.sort((o1, o2) -> o2.getTotalEarnSpeed().compareTo(o1.getTotalEarnSpeed()));
                listMap.put(tempGroupId++, new ArrayList<>(list));
            }
        }

        for (Map.Entry<Integer, List<CrossUnionInfo>> entry : listMap.entrySet()) {
            int groupId = entry.getKey();

            ConcurrentHashMap<String, UnionActivityGroupUnion> map = new ConcurrentHashMap<>();
            int rank = 1;
            for (CrossUnionInfo crossUnionInfo : entry.getValue()) {
                UnionActivityGroupUnion activityGroupUnion = createUnionActivityGroupUnion(info, groupId, crossUnionInfo);
                if(rank <= unionNum){
                    activityGroupUnion.setLocked(1);
                }
                //锁名单时的赚速排名
                activityGroupUnion.setRank(rank++);
                activityGroupUnion.setAbility(crossUnionInfo.getTotalEarnSpeed().toString());
                map.put(crossUnionInfo.getUnionUid(), activityGroupUnion);
            }

            int crossServerId = info.getCrossId().intValue();
            if (needGroup) {
                crossServerId = activityCrossList.get(crossIndex.incrementAndGet() % activityCrossList.size()).getCrossServerId();
            }

            UnionActivityGroup group = new UnionActivityGroup();
            group.setActivityId(info.getActivityId());
            group.setGroupId(groupId);
            group.setCrossServerIdNeedSync(crossServerId);
            group.setServerSetNeedSync(calcServerIdSet(info, map));
            group.setUnionDataMap(map);
            group.setInsertOption();

            groupMap.put(group.getGroupId(), group);
        }
        synchronized (lock) {
            if(Cross3UnionActivityGroupMgr.haveGroup(info.getActivityId())){//已经分完组了
                return;
            }
            // 添加数据
            Cross3UnionActivityGroupMgr.putGroupMap(info.getActivityId(), groupMap);
        }
        // 马上保存一下，没成功的话就交给定时器重试了
        Cross3UnionActivityGroupMgr.saveDbData();

        // 日志
        getLogger().debug("activity {} group success.", info.getActivityId());
        for (UnionActivityGroup group : groupMap.values()) {
            getLogger().debug("activity {} group {} size {}.", info.getActivityId(), group.getGroupId(), group.getUnionDataMap().size());
        }
    }

    /**
     * 同步分组
     */
    public static void checkSyncGroupInfo() {
        for (ActivityInfo info : activityInfoMap.values()) {

            // 活动开始前1小时就可以同步资格了
            long now = System.currentTimeMillis() / 1000;
            if (now < info.getBeginShowTime() - DateHelper.HOUR_MILLIONS || now > info.getEndShowTime()) {
                continue;
            }

            Map<Integer, UnionActivityGroup> groupMap = Cross3UnionActivityGroupMgr.getGroupMap(info.getActivityId());
            if (groupMap == null || !Cross3UnionActivityGroupMgr.haveGroup(info.getActivityId())) {
                continue;
            }

            // 找需要同步的区服和跨服
            Set<Integer> needSyncCrossIdSet = calcNeedSyncCrossIdSet(groupMap);
            Set<Long> needSyncServerIdSet = calcNeedSyncServerIdSet(groupMap);
            if (needSyncCrossIdSet.isEmpty() && needSyncServerIdSet.isEmpty()) {
                continue;
            }

            // 同步
            syncAllGroup(info, groupMap, needSyncCrossIdSet, needSyncServerIdSet);
        }
    }

    /**
     * 无需分组的活动添加商会数据
     * （旧版活动只有一个分组，等玩家登录再生成商会数据）
     */
    public static void checkAddUnionData(long userId) {
        try {

            // 拿商会信息
            CrossUnionMember unionMember = CrossUnionMgr.getUnionMemberByUserId(userId);
            if (unionMember == null) {
                return;
            }
            String unionUid = unionMember.getUnionUid();
            if (StringUtils.isNullOrEmpty(unionUid)) {
                return;
            }
            CrossUnionInfo unionInfo = CrossUnionMgr.getUnionInfo(unionUid);
            if (unionInfo == null || unionInfo.isDelete()) {
                return;
            }
            long serverId = unionMember.getServerId();


            // 找需要检查的活动
            List<ActivityInfo> needCheckActivity = new ArrayList<>();
            for (ActivityInfo activityInfo : activityInfoMap.values()) {

                if (System.currentTimeMillis() >= activityInfo.getEndTime() * 1000) {
                    continue; // 活动过期
                }

                eUnionActivityGroupType groupType = eUnionActivityGroupType.getType(activityInfo.getType());
                if(groupType == null){
                    continue;
                }

                // 服务器ID && 【无需分组活动】 && 有初始数据
                if (activityInfo.getServerIdList().contains(serverId)
                        //有/无需分组活动均可动态加商会，商会有无活动资格由各活动另外判定
                        && !UnionActivityGroupHelper.needGroup(activityInfo)
                        && Cross3UnionActivityGroupMgr.getUnionData(activityInfo.getActivityId(), unionUid) == null) {
                    needCheckActivity.add(activityInfo);
                }else if (activityInfo.getServerIdList().contains(serverId) && groupType.isLockMember() && Cross3UnionActivityGroupMgr.getUnionData(activityInfo.getActivityId(), unionUid) != null){
                    needCheckActivity.add(activityInfo);
                }
            }

            // 没数据的生成数据，有数据看看能不能加成员（成员锁定的情况）
            for (ActivityInfo activityInfo : needCheckActivity) {
                Map<Integer, UnionActivityGroup> groupMap = Cross3UnionActivityGroupMgr.getGroupMap(activityInfo.getActivityId());
                if (groupMap == null) {
                    continue;
                }
                eUnionActivityGroupType groupType = eUnionActivityGroupType.getType(activityInfo.getType());
                UnionActivityGroup targetGroup;
                UnionActivityGroupUnion union;
                synchronized (lock) {

                    //锁名单（商会成员）的新逻辑
                    if(groupType.isLockMember()){//需求改动,锁名单后,名单不在变更
                        continue;
//                        if(checkUserInGroupUnion(activityInfo.getActivityId(), userId)){
//                            continue;
//                        }
//
//                        UnionActivityGroupUnion groupUnion = Cross3UnionActivityGroupMgr.getUnionData(activityInfo.getActivityId(), unionUid);
//                        if(groupUnion != null){
//                            //是否可以加入该商会
//                            if(groupUnion.getUserMap().get(userId) != null){
//                                continue;
//                            }
//
//                            if(groupUnion.getMemberMax() > groupUnion.getUserMap().size()){
//                                UnionActivityGroupUser groupUser = new UnionActivityGroupUser();
//                                //锁名单，新成员只能是普通成员
//                                groupUser.setPosition(eUnionPosition.Member.getValue());
//                                groupUser.setServerId(unionMember.getServerId());
//                                groupUser.setUserId(userId);
//                                groupUnion.getUserMap().put(userId, groupUser);
//                                groupUnion.setUpdateOption();
//                                //清除缓存
//                                Cross3UnionActivityGroupMgr.clearCache(activityInfo.getActivityId());
//                            }else {
//                                continue;
//                            }
//
//                            targetGroup = groupMap.get(groupUnion.getGroupId());
//                            union = groupUnion;
//                        }else {
//                            Random random = new Random();
//                            List<Integer> groupList = new ArrayList<>(groupMap.keySet());
//                            int groupId = groupList.get(random.nextInt(groupList.size()));
//                            targetGroup = groupMap.get(groupId);
//                            union = createUnionActivityGroupUnion(activityInfo, groupId, unionInfo);
//                            //检查每个成员，如果已经在活动的其他分组，则过滤
//                            checkGroupUserRepeated(union);
//                            targetGroup.getUnionDataMap().put(union.getUnionUid(), union);
//                            Cross3UnionActivityGroupMgr.updateGroupUnion(union);
//                        }

                    }else {

                        //不锁名单的走原来的逻辑
                        targetGroup = groupMap.get(UnionActivityGroupHelper.NO_NEED_GROUP_ID);
                        if (targetGroup == null) {
                            continue;
                        }

                        ConcurrentHashMap<String, UnionActivityGroupUnion> unionDataMap = targetGroup.getUnionDataMap();

                        if (unionDataMap.containsKey(unionUid)) {
                            continue;
                        }
                        union = createUnionActivityGroupUnion(activityInfo, targetGroup.getGroupId(), unionInfo);
                        unionDataMap.put(union.getUnionUid(), union);
                    }
                }

                syncUpdateUnion(activityInfo, targetGroup, union);
            }

        } catch (Exception e) {
            getLogger().error("error : ", e);
        }
    }

    /**
     * @param union 待新增的商会名单
     */
    private static void checkGroupUserRepeated(UnionActivityGroupUnion union) {

        List<Long> userList = new ArrayList<>();

        for (Map.Entry<Long, UnionActivityGroupUser> entry : union.getUserMap().entrySet()) {

            //当前成员
            long userId = entry.getKey();

            if(checkUserInGroupUnion(union.getActivityId(), userId)){
                userList.add(userId);
            }

        }

        for (long userId : userList) {
            union.getUserMap().remove(userId);
        }
    }

    /**
     * 检查玩家是否已在活动的分组名单中
     */
    private static boolean checkUserInGroupUnion(int activityId, long userId){
        //遍历已有分组
        Map<Integer, UnionActivityGroup> groupMap = Cross3UnionActivityGroupMgr.getGroupMap(activityId);
        if(groupMap != null){
            //遍历分组
            for (Map.Entry<Integer, UnionActivityGroup> groupEntry : groupMap.entrySet()) {
                for (Map.Entry<String, UnionActivityGroupUnion> unionEntry : groupEntry.getValue().getUnionDataMap().entrySet()) {
                    if(unionEntry.getValue().getUserMap().containsKey(userId)){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 职位变化(锁名单情况)
     */
    public static void updateMemberPosition(String unionUid, long... userIds){
        try {

            CrossUnionInfo unionInfo = CrossUnionMgr.getUnionInfo(unionUid);
            if (unionInfo == null) {
                unionInfo = CrossUnionMgr.getDeleteUnionInfoMap().get(unionUid);
            }
            if (unionInfo == null) {
                return; // 商会信息有问题
            }

            synchronized (lock) {
                Map<Integer, Map<Integer, UnionActivityGroup>> activityGroupMap = Cross3UnionActivityGroupMgr.getGroupMap();
                for (Map.Entry<Integer, Map<Integer, UnionActivityGroup>> entry : activityGroupMap.entrySet()) {
                    int activityId = entry.getKey();
                    ActivityInfo activityInfo = activityInfoMap.get(activityId);
                    if (activityInfo == null || System.currentTimeMillis() >= activityInfo.getEndTime() * 1000) {
                        continue; // 没活动
                    }
                    eUnionActivityGroupType groupType = eUnionActivityGroupType.getType(activityInfo.getType());
                    if(!groupType.isLockMember()){
                        continue;
                    }
                    Map<Integer, UnionActivityGroup> groupMap = entry.getValue();
                    for (UnionActivityGroup group : groupMap.values()) {

                        if (!group.getUnionDataMap().containsKey(unionUid)) {
                            continue; // 没在这个分组
                        }

                        UnionActivityGroupUnion groupUnion = group.getUnionDataMap().get(unionUid);
                        for (long userId : userIds) {
                            UnionMember member = CrossUnionMgr.getUnionMemberByUserId(userId);
                            if(member == null){
                                continue;
                            }
                            UnionActivityGroupUser groupUser = groupUnion.getUserMap().get(member.getUserId());
                            if(groupUser != null){
                                groupUser.setPosition(member.getPosition());
                            }
                        }
                        groupUnion.setUpdateOption();
                        syncUpdateUnion(activityInfo, group, groupUnion);
                    }
                }
            }

        } catch (Exception e) {
            getLogger().error("error : ", e);
        }
    }

    /**
     * 商会发生成员、职位变化
     * （已有分组的商会数据更新下）
     */
    public static void onUnionChange(String unionUid) {
        try {

            CrossUnionInfo unionInfo = CrossUnionMgr.getUnionInfo(unionUid);
            if (unionInfo == null) {
                unionInfo = CrossUnionMgr.getDeleteUnionInfoMap().get(unionUid);
            }
            if (unionInfo == null) {
                return; // 商会信息有问题
            }

            synchronized (lock) {

                Map<Integer, Map<Integer, UnionActivityGroup>> activityGroupMap = Cross3UnionActivityGroupMgr.getGroupMap();
                for (Map.Entry<Integer, Map<Integer, UnionActivityGroup>> entry : activityGroupMap.entrySet()) {
                    int activityId = entry.getKey();
                    ActivityInfo activityInfo = activityInfoMap.get(activityId);
                    if (activityInfo == null || System.currentTimeMillis() >= activityInfo.getEndTime() * 1000) {
                        continue; // 没活动
                    }
                    eUnionActivityGroupType groupType = eUnionActivityGroupType.getType(activityInfo.getType());
                    if(groupType.isLockMember()){
                        continue;
                    }
                    Map<Integer, UnionActivityGroup> groupMap = entry.getValue();
                    for (UnionActivityGroup group : groupMap.values()) {

                        if (!group.getUnionDataMap().containsKey(unionUid)) {
                            continue; // 没在这个分组
                        }

                        UnionActivityGroupUnion union = createUnionActivityGroupUnion(activityInfo, group.getGroupId(), unionInfo);
                        Cross3UnionActivityGroupMgr.updateGroupUnion(union);
                        syncUpdateUnion(activityInfo, group, union);

                    }
                }
            }

        } catch (Exception e) {
            getLogger().error("error : ", e);
        }
    }

    public static void onUserJoinUnion(String unionUid, long userId){
        checkAddUnionData(userId);
    }

    /**
     * 同步整个活动的分组
     */
    private static void syncAllGroup(ActivityInfo info, Map<Integer, UnionActivityGroup> groupMap, Set<Integer> needSyncCrossIdSet, Set<Long> needSyncServerIdSet) {
        UnionActivityGroupProto.UnionActivityGroupSyncReqMsg.Builder builder = UnionActivityGroupPb.parseUnionActivityGroupSyncReqMsgAll(new ArrayList<>(groupMap.values()));
        // 同步跨服
        for (int crossId : needSyncCrossIdSet) {
            MessageHelper.sendUnionActivityGroupPacket(
                    info.getServerIdList().get(new Random().nextInt(info.getServerIdList().size())),
                    0,
                    CrossProtocol.C2_UNION_ACTIVITY_GROUP_SYNC,
                    builder,
                    info.getActivityId(),
                    crossId,
                    -1
            );
            getLogger().info("syncAllGroup timer sync activityId {} to crossID {}.", info.getActivityId(), crossId);
        }
        // 同步区服
        for (long serverId : needSyncServerIdSet) {
            MessageHelper.sendPacket(serverId, 0, YanQuMessageUtils.buildMessage(AgentProtocol.A_UNION_ACTIVITY_GROUP_SYNC, builder));
            getLogger().info("syncAllGroup timer sync activityId {} to serverID {}.", info.getActivityId(), serverId);
        }
    }

    /**
     * 同步商会变化
     */
    public static void syncUpdateUnion(ActivityInfo info, UnionActivityGroup group, UnionActivityGroupUnion union) {
        UnionActivityGroupProto.UnionActivityGroupSyncReqMsg.Builder builder = UnionActivityGroupPb.parseUnionActivityGroupSyncReqMsgUpdate(Collections.singletonList(union));
        // 同步跨服
        MessageHelper.sendUnionActivityGroupPacket(
                union.getUnionBaseInfo().getServerId(),
                0,
                CrossProtocol.C2_UNION_ACTIVITY_GROUP_SYNC,
                builder,
                union.getActivityId(),
                group.getCrossServerId(),
                group.getGroupId()
        );
        // 同步游戏服
        for (long tmpServerId : info.getServerIdList()) {
            MessageHelper.sendPacket(tmpServerId, 0, YanQuMessageUtils.buildMessage(AgentProtocol.A_UNION_ACTIVITY_GROUP_SYNC, builder));
        }
        getLogger().info("syncUpdateUnion sync activityId {}.", info.getActivityId());
    }

    public static Map<Integer, ActivityInfo> getActivityInfoMap() {
        return activityInfoMap;
    }

    /**
     * 尝试多次随机分组，取最佳分组结果
     *
     * @param tryTimes 怕死少来几次
     * @param unionNum 每个组的最大商会数量
     */
    private static List<List<CrossUnionInfo>> getBestRandomGroupResult(ActivityInfo info, List<CrossUnionInfo> unionInfoList, int groupNum, int tryTimes, int unionNum) {
        // 无需分组直接返回
        if (groupNum <= 1 || unionInfoList.isEmpty()) {
            List<List<CrossUnionInfo>> listList = new ArrayList<>();
            listList.add(unionInfoList);
            return listList;
        }

        List<List<CrossUnionInfo>> bestListList = null;
        BigDecimal bestValue = null;
        for (int i = 0; i < tryTimes; i++) {
            // 打乱
            ArrayList<CrossUnionInfo> randomUnionList = new ArrayList<>(unionInfoList);
            Collections.shuffle(randomUnionList);
            // 生成数据
            List<List<CrossUnionInfo>> groupUnionList = new ArrayList<>();
            for (int j = 0; j < groupNum; j++) {
                groupUnionList.add(new ArrayList<>());
            }
            preGroupByRule(info, randomUnionList, groupUnionList, unionNum);
            groupAfterRule(randomUnionList, groupUnionList, unionNum);
            // 拿赚速计算方差
            List<BigInteger> earnSpeedList = new ArrayList<>();
            for (List<CrossUnionInfo> unionList : groupUnionList) {
                BigInteger groupEarnSpeed = BigInteger.ZERO;
                for (CrossUnionInfo unionInfo : unionList) {
                    groupEarnSpeed = groupEarnSpeed.add(unionInfo.getTotalEarnSpeed());
                }
                earnSpeedList.add(groupEarnSpeed);
            }
            BigDecimal variance = MathHelper.calcVariance(earnSpeedList);
            // 比较最佳结果
            if (bestListList == null || variance.compareTo(bestValue) < 0) {
                bestListList = groupUnionList;
                bestValue = variance;
            }
        }

        return bestListList;
    }

    /**
     * 先把不能在一个组的分掉
     */
    private static void preGroupByRule(ActivityInfo info, ArrayList<CrossUnionInfo> randomUnionList, List<List<CrossUnionInfo>> groupUnionList, int unionNum) {

        // 转Map
        Map<String, CrossUnionInfo> allUnionMap = new HashMap<>();
        for (CrossUnionInfo crossUnionInfo : randomUnionList) {
            allUnionMap.put(crossUnionInfo.getUnionUid(), crossUnionInfo);
        }

        // 获取可用规则
        Map<String, UnionNoSameGroup> ruleListMap = new HashMap<>();
        long now = System.currentTimeMillis();
        for (UnionActivityGroupRule rule : new ArrayList<>(groupRuleList)) {
            if (info.getType() == rule.getActivityType() && info.getChildType() == rule.getChildType()) {
                if (rule.getExpireTime() == 0 || now < rule.getExpireTime()) {
                    if (allUnionMap.containsKey(rule.getUnionUid1()) && allUnionMap.containsKey(rule.getUnionUid2())) {
                        // union1
                        if (!ruleListMap.containsKey(rule.getUnionUid1())) {
                            ruleListMap.put(rule.getUnionUid1(), new UnionNoSameGroup(rule.getUnionUid1()));
                        }
                        ruleListMap.get(rule.getUnionUid1()).getSet().add(rule.getUnionUid2());
                        // union2
                        if (!ruleListMap.containsKey(rule.getUnionUid2())) {
                            ruleListMap.put(rule.getUnionUid2(), new UnionNoSameGroup(rule.getUnionUid2()));
                        }
                        ruleListMap.get(rule.getUnionUid2()).getSet().add(rule.getUnionUid1());
                    }
                }
            }
        }

        // 要求高的先处理
        List<UnionNoSameGroup> list = new ArrayList<>(ruleListMap.values());
        Collections.sort(list, new Comparator<UnionNoSameGroup>() {
            @Override
            public int compare(UnionNoSameGroup o1, UnionNoSameGroup o2) {
                return Integer.compare(o1.getSet().size(), o2.getSet().size());
            }
        }.reversed());

        // 存每个组内不欢迎的商会UID
        List<Set<String>> noWelcomeSetList = new ArrayList<>();
        for (int i = 0; i < groupUnionList.size(); i++) {
            noWelcomeSetList.add(new HashSet<>());
        }

        // 分
        Random random = new Random();
        for (UnionNoSameGroup data : list) {
            CrossUnionInfo crossUnionInfo = allUnionMap.get(data.getUnionUid());
            if (crossUnionInfo == null) {
                continue;
            }
            // 可加入的分组
            List<Integer> canJoinList = new ArrayList<>();
            for (int i = 0; i < noWelcomeSetList.size(); i++) {
                if (noWelcomeSetList.get(i).contains(data.getUnionUid())) {
                    continue;
                }
                if (groupUnionList.get(i).size() >= unionNum) {
                    continue;
                }
                canJoinList.add(i);
            }
            if (canJoinList.isEmpty()) {
                continue;
            }

            // 随机找分组
            int index = canJoinList.get(random.nextInt(canJoinList.size()));
            // 加入分组
            groupUnionList.get(index).add(crossUnionInfo);
            // 【移出原始数组，避免后面又分一次】
            randomUnionList.removeIf(item -> data.getUnionUid().equals(item.getUnionUid()));
            // 添加该分组不欢迎的商会
            noWelcomeSetList.get(index).addAll(data.getSet());
        }
    }

    /**
     * 其它的按顺序填到数量够为止
     */
    private static void groupAfterRule(ArrayList<CrossUnionInfo> randomUnionList, List<List<CrossUnionInfo>> groupUnionList, int unionNum) {
        int index = 0;
        for (List<CrossUnionInfo> list : groupUnionList) {
            while (list.size() < unionNum && index < randomUnionList.size()) {
                list.add(randomUnionList.get(index++));
            }
        }
    }

    // ------------------------------------------------------------

    public static boolean activityInShowTime(ActivityInfo activityInfo) {
        if (activityInfo == null) {
            return false;
        }
        long now = System.currentTimeMillis() / 1000;
        return now >= activityInfo.getBeginShowTime() && now <= activityInfo.getEndShowTime();
    }

    private static List<CrossUnionInfo> getActivityUnionList(ActivityInfo info) {

        // 是否只要活跃商会
        boolean checkActive = false;
        eUnionActivityGroupType type = eUnionActivityGroupType.getType(info.getType());
        if (type != null && !type.isLimitUnionNum() && UnionActivityGroupHelper.needGroup(info)) {
            checkActive = true;
        }

        List<CrossUnionInfo> list = new ArrayList<>();
        HashSet<Long> serverIdSet = new HashSet<>(info.getServerIdList());
        List<CrossUnionInfo> unionListByServerList = CrossUnionMgr.getUnionListByServerList(serverIdSet);
        for (CrossUnionInfo crossUnionInfo : unionListByServerList) {
            if (crossUnionInfo.isDelete()) {
                continue;
            }
            if (checkActive) {
                if (CrossUnionConfigMgr.getUnionLv(crossUnionInfo.getExperience()) < 3 && !isActiveUnion(crossUnionInfo)) {
                    continue;
                }
            }
            list.add(crossUnionInfo);
        }
        return list;
    }

    private static boolean isActiveUnion(CrossUnionInfo crossUnionInfo) {
        Map<Long, CrossUnionMember> memberMap = CrossUnionMgr.getUnionMemberMap(crossUnionInfo.getUnionUid());
        if (memberMap != null) {
            long activeTime = System.currentTimeMillis() / 1000 - DateHelper.DAY_SECONDS * 7;
            for (CrossUnionMember member : memberMap.values()) {
                // 从member拿info
                UserBaseInfo info = member.getUserBaseInfo();
                if (info.getLastLoginTime() > activeTime) {
                    return true;
                }
                // 从CrossUserMgr随便拿info随便看看
                CrossUserBaseInfo baseInfo = CrossUserMgr.getMemUserBaseInfo(member.getUserId());
                if (baseInfo != null) {
                    if (baseInfo.getUserBaseInfo().getLastLoginTime() > activeTime) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private static UnionActivityGroupUnion createUnionActivityGroupUnion(ActivityInfo activityInfo, int groupId, CrossUnionInfo crossUnionInfo) {

        ConcurrentHashMap<Long, UnionActivityGroupUser> userMap = new ConcurrentHashMap<>();
        Map<Long, CrossUnionMember> memberMap = CrossUnionMgr.getUnionMemberMap(crossUnionInfo.getUnionUid());
        if (memberMap != null) {
            for (CrossUnionMember member : memberMap.values()) {
                userMap.put(member.getUserId(), createUnionActivityGroupUser(member));
            }
        }

        int crossServerCount = CrossUnionServerGroupMgr.getGroupServerCountByServerId(crossUnionInfo.getServerId());
        int memberMaxLimit = CrossUnionConfigMgr.getMaxMemberCount(crossUnionInfo.getExperience(), crossUnionInfo.isCross(), crossServerCount);
        UnionActivityGroupUnion data = new UnionActivityGroupUnion();
        data.setActivityId(activityInfo.getActivityId());
        data.setGroupId(groupId);
        data.setUnionUid(crossUnionInfo.getUnionUid());
        data.setUnionBaseInfo(CrossUnionMgr.parseUnionBaseInfo(crossUnionInfo));
        data.setUserMap(userMap);
        data.setMemberMax(memberMaxLimit);
        data.setInsertOption();
        return data;
    }

    private static UnionActivityGroupUser createUnionActivityGroupUser(CrossUnionMember crossUnionMember) {
        UnionActivityGroupUser data = new UnionActivityGroupUser();
        data.setUserId(crossUnionMember.getUserId());
        data.setServerId(crossUnionMember.getServerId());
        data.setPosition(crossUnionMember.getPosition());
        return data;
    }

    /**
     * 计算分组涉及的区服
     */
    private static Set<Long> calcServerIdSet(ActivityInfo info, Map<String, UnionActivityGroupUnion> map) {

        // 无需分组活动的区服全部涉及
        if (!UnionActivityGroupHelper.needGroup(info)) {
            return new HashSet<>(info.getServerIdList());
        }

        // 拿活动分组内，商会对应的商会分组
        Set<Integer> unionGroupIdSet = new HashSet<>();
        for (UnionActivityGroupUnion union : map.values()) {
            int unionGroupId = CrossUnionServerGroupMgr.getGroupIdByServerId(union.getUnionBaseInfo().getServerId());
            unionGroupIdSet.add(unionGroupId);
        }
        // 拿分组内的区服
        Set<Long> serverIdSet = new HashSet<>();
        for (int unionGroupId : unionGroupIdSet) {
            serverIdSet.addAll(CrossUnionServerGroupMgr.getGroupServer(unionGroupId));
        }
        return serverIdSet;
    }

    private static Set<Long> calcNeedSyncServerIdSet(Map<Integer, UnionActivityGroup> groupMap) {
        Set<Long> set = new HashSet<>();
        for (UnionActivityGroup group : groupMap.values()) {
            set.addAll(group.getNoSyncServerSet());
        }
        return set;
    }

    private static Set<Integer> calcNeedSyncCrossIdSet(Map<Integer, UnionActivityGroup> groupMap) {
        Set<Integer> set = new HashSet<>();
        for (UnionActivityGroup group : groupMap.values()) {
            if (!group.isSyncCrossServer()) {
                set.add(group.getCrossServerId());
            }
        }
        return set;
    }


    // ------------------------------------------------------------

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    private void initCrossList() {
        // 获取活动跨服
        int channelId = ConfigHelper.getInt("channelId");
        List<CrossServerInfo> list = new CrossServerInfoDaoImpl().getAllChannelCrossServerInfo(channelId).stream()
                .filter(item -> item.getCrossServerType() == CrossServerType.ACTIVITY_CROSS)
                .collect(Collectors.toList());

        // 内网测试处理
        UnionActivityGroupLockTest.handleTestCrossList(list);

        // 活动跨服达到4台，就不指定跨域转发的那台了
        if (list.size() >= 4) {
            long routeChannelCrossId = ChannelConfig.CHANNEL_ACTIVITY_CROSS_SERVER_ID;
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getCrossServerId() == routeChannelCrossId) {
                    CrossServerInfo remove = list.remove(i);
                    getLogger().debug("商会活动分组  移除可选活动跨服 {}", remove.getCrossServerId());
                    break;
                }
            }
        }

        activityCrossList = list;
    }

    private void initGroupRuleList() {
        groupRuleList = UnionActivityGroupBusiness.getUnionActivityGroupRuleList();
        getLogger().debug("groupRuleList size {}.", groupRuleList.size());
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        if (null == threadTaskManger) {
            threadTaskManger = new ThreadTaskManger(1, "UnionActivityGroupLockMgr", 2);
        }
        initCrossList();
        initGroupRuleList();
        reloadUnionActivityConfig();
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    public static List<CrossServerInfo> getActivityCrossList() {
        return activityCrossList;
    }

    public static ThreadTaskManger getThreadTaskManger() {
        return threadTaskManger;
    }
}
